<?php
/**
 * Created by PhpStorm.
 * User: jaylen
 * Date: 2020-05-28
 * Time: 15:06
 */

namespace app\admin\model\traits;


use think\facade\Db;

trait ModelTableTraits
{

    protected static $array_data_type = [3,8,9];    //传过来的数据是以数组的形式


    /**
     * 创建模型表
     * @param array $data
     */
    protected function createModelTable(array $data)
    {
        $sql = "CREATE TABLE `{$this->database}`.`{$this->database_prefix}{$data['en_name']}` ( ";

        // 添加主键
        $sql .= "`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键',";

        foreach ($data['fields_data'] as $key => $value) {
            $sql .= "`{$value['en_name']}` " . $this->getSqlByFieldType($value['type']) . " COMMENT '{$value['cn_name']}',";
        }

        // 删除最后一个字段的最后一个字符，
        // $sql = trim($sql,',');

        $sql .= "PRIMARY KEY (`id`)";

        $sql .= " ) CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '保存{$data['cn_name']}的信息';";

        Db::execute($sql);
    }

    /**
     * 新增模型字段
     * @param $table_name
     * @param $data
     */
    protected function addModelFields($table_name, $data)
    {
        if (!empty($data)) {
            $sql = "ALTER TABLE `{$this->database}`.`{$this->database_prefix}{$table_name}` ";

            foreach ($data as $value) {
                $sql .= "ADD COLUMN `{$value['en_name']}` " . $this->getSqlByFieldType($value['type']) . " COMMENT '{$value['cn_name']}',";
            }

            // 删除最后一个字段的最后一个字符，
            $sql = trim($sql,',');
            $sql .= ";";

            Db::execute($sql);
        }
    }

    /**
     * 修改模型表的字段信息
     * @param $table_name
     * @param array $data
     * @return array
     */
    protected function changeModelFields($table_name,array $data)
    {
        $needDeleteFile = [];

        $sql = "ALTER TABLE `{$this->database}`.`{$this->database_prefix}{$table_name}` ";

        // 修改字段的注释
        if (!empty($data['cn_name'])) {
            foreach ($data['cn_name'] as $value) {
                $sql .= "MODIFY COLUMN `{$value['en_name']}` ".$this->getSqlByFieldType($value['type'])." COMMENT '{$value['new_cn_name']}',";
            }
        }

        // 修改字段的类型
        if (!empty($data['type'])) {
            // 如果旧的字段类型中是包含图片的，需要先删除原本的图片
            foreach ($data['type'] as $value) {
                if (isset($value['new_en_name']) && !empty($value['new_en_name'])) {
                    $sql .= "CHANGE COLUMN `{$value['en_name']}` `{$value['new_en_name']}` " . $this->getSqlByFieldType($value['new_type']) . " COMMENT '{$value['cn_name']}',";
                } else {
                    $sql .= "MODIFY COLUMN `{$value['en_name']}` " . $this->getSqlByFieldType($value['new_type']) . " COMMENT '{$value['cn_name']}',";
                }

                switch ($value['old_type']) {
                    // 富文本
                    case 6:
                        $imageData = $this->getTableFieldsData($table_name, $value['en_name']);
                        foreach ($imageData as $image) {
                            $needDeleteFile = array_merge($needDeleteFile, static::getRichTextImage($image));
                        }
                        break;
                    // 附件
                    case 9:
                        $fileData = $this->getTableFieldsData($table_name, $value['en_name']);
                        $delete_file = [];
                        foreach ($fileData as $file_item) {
                            $file_item = json_decode($file_item, true);
                            $delete_file = array_merge($delete_file, array_column($file_item, 'url'));
                        }
                        $needDeleteFile = array_merge($needDeleteFile, $delete_file);
                        break;
                }
            }

            // 清空对应字段列的值
            $this->clearModelFieldsValueData($table_name, $data['type']);
        }

        // 修改字段的值
        if (!empty($data['en_name'])) {
            foreach ($data['en_name'] as $value) {
                $sql .= "CHANGE COLUMN `{$value['old_en_name']}` `{$value['new_en_name']}` " . $this->getSqlByFieldType($value['type']) . " COMMENT '{$value['cn_name']}',";
            }
        }

        // 删除最后一个字段的最后一个字符，
        $sql = trim($sql,',');
        $sql .= ";";

        if (!empty($data['cn_name']) || !empty($data['en_name']) || !empty($data['type'])) {
            Db::execute($sql);
        }

        return $needDeleteFile;
    }

    /**
     * 删除模型字段数据
     * @param $table_name
     * @param $data
     * @return array
     */
    protected function delModelFields($table_name, $data)
    {

        $needDelImage = [];

        if (!empty($data)) {
            $sql = "ALTER TABLE `{$this->database}`.`{$this->database_prefix}{$table_name}` ";

            foreach ($data as $value) {
                $sql .= "DROP COLUMN `{$value['en_name']}` ,";
                switch ($value['type']) {
                    // 富文本
                    case 6:
                        $imageData = $this->getTableFieldsData($table_name, $value['en_name']);
                        foreach ($imageData as $image) {
                            $needDelImage = array_merge($needDelImage, static::getRichTextImage($image));
                        }
                        break;
                }
            }

            // 删除最后一个字段的最后一个字符，
            $sql = trim($sql,',');
            $sql .= ";";

            Db::execute($sql);
        }

        return $needDelImage;
    }

    /**
     * 通过字段类型获取对应的sql语句
     * @param $type
     * @return string|null
     */
    private function getSqlByFieldType($type)
    {

        // 如果需要将text、blob类型设置默认值，需要将mysql的配置文件的sql_mode的设置设置为空或者注释

        $sql = null;
        $type = intval($type);
        switch ($type) {
            case 1:
            case 7:
            case 9:
                $sql = "varchar(600) NOT NULL DEFAULT ''";
                break;
            case 5:
            case 8:
                $sql = "text NOT NULL";
                break;
            case 6:
                $sql = "longtext NOT NULL";
                break;
            case 10:
                $sql = "int(10) UNSIGNED NOT NULL DEFAULT 0";
                break;
            case 11:
                $sql = "double(10, 2) UNSIGNED NOT NULL DEFAULT 0";
                break;
            case 2:
            case 3:
            case 4:
            default:
                $sql = "varchar(100) NOT NULL DEFAULT ''";
                break;
        }

        return $sql;
    }

    /**
     * 获取修改后已变更的数据
     * @param $data
     * @return array
     */
    private function getDiffModelFieldsData(&$data)
    {
        if (empty($data)) {
            return [];
        }

        $diffData = [
            'change_field' => [
                'cn_name' => [],
                'en_name' => [],
                'type' => [],
            ],
            'delete_field' => [],
            'add_field' => [],
        ];

        // 获取旧的模型字段数据
        $old_model_fields_data = $this->modelFields()->column('id,cn_name,en_name,type');
        $old_model_fields_id = array_column($old_model_fields_data, 'id');
        $new_model_fields_id = array_reduce($data, function ($v, &$item) use ($old_model_fields_id,$old_model_fields_data,&$diffData) {
            if (isset($item['id']) && !empty($item['id'])) {
                $v[] = $item['id'];
                $diff = [];
                $old_data_pos = array_search($item['id'],$old_model_fields_id);
                unset($item['id']);
                if ($old_data_pos !== false) {
                    // 取出需要修改的字段信息
                    if ($item['type'] != $old_model_fields_data[$old_data_pos]['type']) {
                        $diff['en_name'] = $old_model_fields_data[$old_data_pos]['en_name'];
                        $diff['cn_name'] = $item['cn_name'];
                        $diff['old_type'] = $old_model_fields_data[$old_data_pos]['type'];
                        $diff['new_type'] = $item['type'];

                        // 判断字段名是否同时被修改了
                        if ($item['en_name'] != $old_model_fields_data[$old_data_pos]['en_name']) {
                            $diff['new_en_name'] = $item['en_name'];
                        }
                        $diffData['change_field']['type'][] = $diff;

                        return $v;
                    }

                    if ($item['en_name'] != $old_model_fields_data[$old_data_pos]['en_name']) {
                        $diff['type'] = $item['type'];
                        $diff['cn_name'] = $item['cn_name'];
                        $diff['old_en_name'] = $old_model_fields_data[$old_data_pos]['en_name'];
                        $diff['new_en_name'] = $item['en_name'];
                        $diffData['change_field']['en_name'][] = $diff;

                        return $v;
                    }

                    if ($item['cn_name'] != $old_model_fields_data[$old_data_pos]['cn_name']) {
                        $diff['en_name'] = $old_model_fields_data[$old_data_pos]['en_name'];
                        $diff['type'] = $item['type'];
                        $diff['new_cn_name'] = $item['cn_name'];
                        $diffData['change_field']['cn_name'][] = $diff;
                        return $v;
                    }
                }
            } else {
                // 取出是新增的字段（没有id字段信息）
                $diffData['add_field'][] = $item;
            }
            return $v;
        }, []);

        // 比较新旧id，取出差集，这样就可以得出那些被删除了
        $delete_model_fields_id = array_diff($old_model_fields_id, $new_model_fields_id);
        $diffData['delete_field'] = array_reduce($old_model_fields_data, function ($v, $item) use ($delete_model_fields_id) {
            if (in_array($item['id'], $delete_model_fields_id)) {
                $v[] = $item;
            }
            return $v;
        }, []);

        return $diffData;

    }

    /**
     * 获取模型表指定字段的全部数据
     * @param $table_name
     * @param $field
     * @return array
     */
    private function getTableFieldsData($table_name, $field)
    {
        $data = Db::name($table_name)->where($field, '<>', '')
            ->column($field);

        if (!$data) {
            return [];
        }

        return $data;
    }

    /**
     * 清空模型表对应字段的值
     * @param $table_name
     * @param $data
     */
    private function clearModelFieldsValueData($table_name, $data)
    {
        // 清空修改了类型的数据
        if (!empty($data)) {
            $sql = "UPDATE `{$this->database}`.`{$this->database_prefix}{$table_name}` SET ";
            foreach ($data as $value) {
                $sql .= "`{$value['en_name']}` = '',";
            }
            // 删除最后一个字段的最后一个字符，
            $sql = trim($sql,',');
            $sql .= ";";

            Db::execute($sql);
        }
    }

    /**
     * 处理前端提交过来的模型字段数据
     * @param $data
     */
    private static function handleSubmitModelTableData(&$data)
    {
//        foreach ($data['fields_data'] as $key => $value) {
//            if (empty($value['cn_name']) || empty($value['en_name'])) {
//                array_splice($data['fields_data'], $key, 1);
//                continue ;
//            }
//        }
//        $len = count($data['fields_data']);
//        for ($i = 0; $i < $len; $i++) {
//            if (empty($data['fields_data'][$i]['cn_name']) || empty($data['fields_data'][$i]['en_name'])) {
//                array_splice($data['fields_data'], $i, 1);
//                $i--;
//                $len--;
//                continue ;
//            }
//        }
        $sort = 1;
        foreach ($data['fields_data'] as $key => &$value) {
            if (empty($value['cn_name']) || empty($value['en_name'])) {
                unset($data['fields_data'][$key]);
                continue ;
            }
            $value['sort'] = $sort++;
        }
        $data['fields_data'] = array_values($data['fields_data']);
    }

    /**
     * 根据模型表和模型表对应的id重组字段数据
     * @param array $fields
     * @param string $table_name
     * @param int $table_id
     * @return array
     */
    private static function recombinantFieldsData(array $fields, $table_name = '', $table_id = 0)
    {
        if (empty($fields) || !is_array($fields)) {
            return [];
        }

        if (empty($table_name)) {
            foreach ($fields as &$field) {
                if (in_array($field['type'], self::$array_data_type)) {
                    $field['value'] = [];
                    continue ;
                }
                $field['value'] = '';
            }
        } else {
            // 获取数据库中模型表中的数据
            $table_data = Db::name($table_name)
                ->where('id','=',$table_id)
                ->find();

            if (empty($table_data)) {
                foreach ($fields as &$field) {
                    if (in_array($field['type'], self::$array_data_type)) {
                        $field['value'] = [];
                        continue ;
                    }
                    $field['value'] = '';
                }
            } else {
                foreach ($fields as &$field) {
                    if (in_array($field['type'], self::$array_data_type)) {
                        $field['value'] = json_decode($table_data[$field['en_name']], true);
                    } else {
                        $field['value'] = $table_data[$field['en_name']];
                    }
                }
            }
        }

        return $fields;
    }
}